<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>2.视图抽象定义 | 被删的前端游乐场</title>
    <meta name="generator" content="VuePress 1.8.2">
    
    <meta name="description" content="Just playing around">
    
    <link rel="preload" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css" as="style"><link rel="preload" href="/front-end-playground/assets/js/app.1e2670bf.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/2.38d016d1.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/3.e3f029cb.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/107.b1eeddc4.js" as="script">
    <link rel="stylesheet" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/front-end-playground/" class="home-link router-link-active"><!----> <span class="site-name">被删的前端游乐场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>Angular框架解读</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-0-prestart.html" class="sidebar-link">0.预热篇</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-metadata.html" class="sidebar-link">1.元数据和装饰器</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-dom-define.html" aria-current="page" class="active sidebar-link">2.视图抽象定义</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-dom-define.html#各抽象类视图定义" class="sidebar-link">各抽象类视图定义</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-dom-define.html#angular-中的视图" class="sidebar-link">Angular 中的视图</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-dom-define.html#总结" class="sidebar-link">总结</a></li></ul></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-zonejs.html" class="sidebar-link">3.Zone区域之zone.js</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-zone-ngzone.html" class="sidebar-link">4.Zone区域之ngZone</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-module.html" class="sidebar-link">5.模块化组织</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-1-basic-concepts.html" class="sidebar-link">6.依赖注入的基本概念</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-2-hierarchical-di.html" class="sidebar-link">7.多级依赖注入设计</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-3-bootstrap.html" class="sidebar-link">8.依赖注入的引导过程</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-0-design.html" class="sidebar-link">9.Ivy编译器整体设计</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-1-view-data-and-node-injector.html" class="sidebar-link">10.Ivy编译器的视图数据和依赖解析</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>玩转 Angular</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Cycle.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>D3.js 和 Tree</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Three.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>BOX2D.js 文档与教程</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><p>作为“为大型前端项目”而设计的前端框架，Angular 其实有许多值得参考和学习的设计，本系列主要用于研究这些设计和功能的实现原理。本文主要围绕 Angular 中与视图有关的一些定义进行介绍。</p> <h1 id="angular-中的视图抽象"><a href="#angular-中的视图抽象" class="header-anchor">#</a> Angular 中的视图抽象</h1> <p>Angular 版本可在不同的平台上运行：在浏览器中、在移动平台上或在 Web Worker 中。因此，需要特定级别的抽象来介于平台特定的 API 和框架接口之间。</p> <p>Angular 中通过抽象封装了不同平台的差异，并以下列引用类型的形式出现：<code>ElementRef</code>，<code>TemplateRef</code>，<code>ViewRef</code>，<code>ComponentRef</code>和<code>ViewContainerRef</code>。</p> <h2 id="各抽象类视图定义"><a href="#各抽象类视图定义" class="header-anchor">#</a> 各抽象类视图定义</h2> <p>在阅读源码的时候，如果不清楚这些定义之间的区别，很容易搞混淆。所以，这里我们先来理解下它们之间的区别。</p> <h3 id="元素-elementref"><a href="#元素-elementref" class="header-anchor">#</a> 元素 ElementRef</h3> <p><code>ElementRef</code>是最基本的抽象。如果观察它的类结构，可以看到它仅包含与其关联的本地元素：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">ElementRef<span class="token operator">&lt;</span><span class="token constant">T</span> <span class="token operator">=</span> <span class="token builtin">any</span><span class="token operator">&gt;</span></span> <span class="token punctuation">{</span>
  <span class="token comment">// 基础原生元素</span>
  <span class="token comment">// 如果不支持直接访问原生元素（例如当应用程序在 Web Worker 中运行时），则为 null</span>
  <span class="token keyword">public</span> nativeElement<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">;</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span>nativeElement<span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>nativeElement <span class="token operator">=</span> nativeElement<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>该 API 可用于直接访问本地 DOM 元素，可以比作<code>document.getElementById('myId')</code>。但 Angular 并不鼓励直接使用，尽可能使用 Angular 提供的模板和数据绑定。</p> <h3 id="模板-templateref"><a href="#模板-templateref" class="header-anchor">#</a> 模板 TemplateRef</h3> <p>在 Angular 中，模板用来定义要如何在 HTML 中渲染组件视图的代码。</p> <p>模板通过<code>@Component()</code>装饰器与组件类类关联起来。模板代码可以作为<code>template</code>属性的值用内联的方式提供，也可以通过 <code>templateUrl</code>属性链接到一个独立的 HTML 文件。</p> <p>用<code>TemplateRef</code>对象表示的其它模板用来定义一些备用视图或内嵌视图，它们可以来自多个不同的组件。<code>TemplateRef</code>是一组 DOM 元素（<code>ElementRef</code>），可在整个应用程序的视图中重复使用：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">TemplateRef<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span></span> <span class="token punctuation">{</span>
  <span class="token comment">// 此嵌入视图的父视图中的 anchor 元素</span>
  <span class="token keyword">abstract</span> <span class="token keyword">get</span> <span class="token function">elementRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> ElementRef<span class="token punctuation">;</span>
  <span class="token comment">// 基于此模板实例化嵌入式视图，并将其附加到视图容器</span>
  <span class="token keyword">abstract</span> <span class="token function">createEmbeddedView</span><span class="token punctuation">(</span>context<span class="token operator">:</span> <span class="token constant">C</span><span class="token punctuation">)</span><span class="token operator">:</span> EmbeddedViewRef<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>就其本身而言，<code>TemplateRef</code>类是一个简单的类，仅包括：</p> <ul><li><code>elementRef</code>属性：拥有对其宿主元素的引用</li> <li><code>createEmbeddedView</code>方法：它允许我们创建视图并将其引用作为<code>ViewRef</code>返回。</li></ul> <p>模板会把纯 HTML 和 Angular 的数据绑定语法、指令和模板表达式组合起来。Angular 的元素会插入或计算那些值，以便在页面显示出来之前修改 HTML 元素。</p> <h2 id="angular-中的视图"><a href="#angular-中的视图" class="header-anchor">#</a> Angular 中的视图</h2> <p>在 Angular 中，视图是可显示元素的最小分组单位，它们会被同时创建和销毁。Angular 哲学鼓励开发人员将 UI 视为视图的组合（而不是独立的 html 标签树）。</p> <p>组件(<code>component</code>) 类及其关联的模板(<code>template</code>)定义了一个视图。具体实现上，视图由一个与该组件相关的<code>ViewRef</code>实例表示。</p> <h3 id="viewref"><a href="#viewref" class="header-anchor">#</a> ViewRef</h3> <p><code>ViewRef</code>表示一个 Angular 视图：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">declare</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">ViewRef</span> <span class="token keyword">extends</span> <span class="token class-name">ChangeDetectorRef</span> <span class="token punctuation">{</span>
    <span class="token comment">// 销毁该视图以及与之关联的所有数据结构</span>
    <span class="token keyword">abstract</span> <span class="token keyword">get</span> <span class="token function">destroyed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span>
    <span class="token comment">// 报告此视图是否已被销毁</span>
    <span class="token keyword">abstract</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
    <span class="token comment">// 生命周期挂钩，为视图提供其他开发人员定义的清理功能</span>
    <span class="token keyword">abstract</span> <span class="token function">onDestroy</span><span class="token punctuation">(</span>callback<span class="token operator">:</span> <span class="token builtin">Function</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>其中，<code>ChangeDetectorRef</code>提供更改检测功能的基类，用于更改检测树收集所有要检查更改的视图：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">declare</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">ChangeDetectorRef</span> <span class="token punctuation">{</span>
    <span class="token comment">// 当输入已更改或视图中触发了事件时，通常会将组件标记为脏（需要重新渲染）</span>
    <span class="token comment">// 调用此方法以确保即使没有发生这些触发器，也要检查组件</span>
    <span class="token keyword">abstract</span> <span class="token function">checkNoChanges</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
    <span class="token comment">// 从变更检测树中分离该视图。在重新连接分离视图之前，不会对其进行检查。</span>
    <span class="token comment">// 与 detectChanges() 结合使用可实现本地变更检测检查</span>
    <span class="token keyword">abstract</span> <span class="token function">detach</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
    <span class="token comment">// 检查此视图及其子级，与 detach() 结合使用可实现本地更改检测检查</span>
    <span class="token keyword">abstract</span> <span class="token function">detectChanges</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
    <span class="token comment">// 检查变更检测器及其子级，如果检测到任何变更，则抛出该异常</span>
    <span class="token keyword">abstract</span> <span class="token function">markForCheck</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
    <span class="token comment">// 将先前分离的视图重新附加到变更检测树</span>
    <span class="token comment">// 默认情况下，视图将附加到树上</span>
    <span class="token keyword">abstract</span> <span class="token function">reattach</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="两种类型的视图"><a href="#两种类型的视图" class="header-anchor">#</a> 两种类型的视图</h3> <p>Angular 支持两种类型的视图：</p> <p><strong>(1) 链接到模板（<code>template</code>）的嵌入式视图（<code>embeddedView</code>）。</strong></p> <p>嵌入式视图表示视图容器中的 Angular 视图。模板只是保存视图的蓝图，可以使用上述的<code>createEmbeddedView</code>方法从模板实例化视图。</p> <p><strong>(2) 链接到组件（<code>component</code>）的宿主视图（<code>hostView</code>）。</strong></p> <p>直属于某个组件的视图叫做宿主视图。</p> <p>宿主视图是在动态实例化组件时创建的，可以使用<code>ComponentFactoryResolver</code>动态创建实例化一个组件。在 Angular 中，每个组件都绑定到特定的注入器实例，因此在创建组件时我们将传递当前的注入器实例。</p> <p>视图中各个元素的属性可以动态修改以响应用户的操作，而这些元素的结构（数量或顺序）则不能。你可以通过在它们的视图容器（<code>ViewContainer</code>）中插入、移动或移除内嵌视图来修改这些元素的结构。</p> <h3 id="viewcontainerref"><a href="#viewcontainerref" class="header-anchor">#</a> ViewContainerRef</h3> <p><code>ViewContainerRef</code>是可以将一个或多个视图附着到组件中的容器：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">declare</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">ViewContainerRef</span> <span class="token punctuation">{</span>
    <span class="token comment">// 锚元素，用于指定此容器在包含视图中的位置</span>
    <span class="token comment">// 每个视图容器只能有一个锚元素，每个锚元素只能有一个视图容器</span>
    <span class="token keyword">abstract</span> <span class="token keyword">get</span> <span class="token function">element</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> ElementRef<span class="token punctuation">;</span>
    <span class="token comment">// 此视图容器的 DI</span>
    <span class="token keyword">abstract</span> <span class="token keyword">get</span> <span class="token function">injector</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Injector<span class="token punctuation">;</span>
    <span class="token comment">// 此容器当前附加了多少视图</span>
    <span class="token keyword">abstract</span> <span class="token keyword">get</span> <span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
    <span class="token comment">// 销毁此容器中的所有视图</span>
    <span class="token keyword">abstract</span> <span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
    <span class="token comment">// 实例化单个组件，并将其宿主视图插入此容器</span>
    <span class="token keyword">abstract</span> <span class="token generic-function"><span class="token function">createComponent</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>componentFactory<span class="token operator">:</span> ComponentFactory<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> index<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> injector<span class="token operator">?</span><span class="token operator">:</span> Injector<span class="token punctuation">,</span> projectableNodes<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> ngModule<span class="token operator">?</span><span class="token operator">:</span> NgModuleRef<span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token operator">:</span> ComponentRef<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
    <span class="token comment">// 实例化一个嵌入式视图并将其插入</span>
    <span class="token keyword">abstract</span> <span class="token generic-function"><span class="token function">createEmbeddedView</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>templateRef<span class="token operator">:</span> TemplateRef<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token punctuation">,</span> context<span class="token operator">?</span><span class="token operator">:</span> <span class="token constant">C</span><span class="token punctuation">,</span> index<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> EmbeddedViewRef<span class="token operator">&lt;</span><span class="token constant">C</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
    <span class="token comment">// 从此容器分离视图而不销毁它</span>
    <span class="token keyword">abstract</span> <span class="token function">detach</span><span class="token punctuation">(</span>index<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> ViewRef <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token comment">// 从此容器检索视图</span>
    <span class="token keyword">abstract</span> <span class="token function">get</span><span class="token punctuation">(</span>index<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> ViewRef <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token comment">// 返回当前容器内视图的索引</span>
    <span class="token keyword">abstract</span> <span class="token function">indexOf</span><span class="token punctuation">(</span>viewRef<span class="token operator">:</span> ViewRef<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
    <span class="token comment">// 将视图移动到此容器中的新位置</span>
    <span class="token keyword">abstract</span> <span class="token function">insert</span><span class="token punctuation">(</span>viewRef<span class="token operator">:</span> ViewRef<span class="token punctuation">,</span> index<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> ViewRef<span class="token punctuation">;</span>
    <span class="token keyword">abstract</span> <span class="token function">move</span><span class="token punctuation">(</span>viewRef<span class="token operator">:</span> ViewRef<span class="token punctuation">,</span> currentIndex<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> ViewRef<span class="token punctuation">;</span>
    <span class="token comment">// 销毁附加到此容器的视图</span>
    <span class="token keyword">abstract</span> <span class="token function">remove</span><span class="token punctuation">(</span>index<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>任何 DOM 元素都可以用作视图容器，Angular 不会在元素内插入视图，而是将它们附加到绑定到<code>ViewContainer</code>的元素之后。</p> <blockquote><p>通常，标记<code>ng-container</code>元素是标记应创建<code>ViewContainer</code>的位置的最佳选择。它作为注释呈现，因此不会在 DOM 中引入多余的 HTML 元素。</p></blockquote> <p>通过<code>ViewContainerRef</code>，可以用<code>createComponent()</code>方法实例化组件时创建宿主视图，也可以用 <code>createEmbeddedView()</code>方法实例化<code>TemplateRef</code>时创建内嵌视图。</p> <p>视图容器的实例还可以包含其它视图容器，以创建层次化视图（视图树）。</p> <h3 id="视图树-view-hierarchy"><a href="#视图树-view-hierarchy" class="header-anchor">#</a> 视图树（View hierarchy）</h3> <p>在 Angular 中，通常会把视图组织成一些视图树（view hierarchies）。视图树是一棵相关视图的树，它们可以作为一个整体行动，是 Angular 变更检测的关键部件之一。</p> <p>视图树的根视图就是组件的宿主视图。宿主视图可以是内嵌视图树的根，它被收集到了宿主组件上的一个视图容器（<code>ViewContainerRef</code>）中。当用户在应用中导航时（比如使用路由器），视图树可以动态加载或卸载。</p> <p>视图树和组件树并不是一一对应的：</p> <ul><li>嵌入到指定视图树上下文中的视图，也可能是其它组件的宿主视图</li> <li>组件可能和宿主组件位于同一个<code>NgModule</code>中，也可能属于其它<code>NgModule</code></li></ul> <h3 id="组件、模板、视图与模块"><a href="#组件、模板、视图与模块" class="header-anchor">#</a> 组件、模板、视图与模块</h3> <p>在 Angular 中，可以通过组件的配套模板来定义其视图。模板就是一种 HTML，它会告诉 Angular 如何渲染该组件。</p> <p>视图通常会分层次进行组织，让你能以 UI 分区或页面为单位进行修改、显示或隐藏。与组件直接关联的模板会定义该组件的宿主视图。该组件还可以定义一个带层次结构的视图，它包含一些内嵌的视图作为其它组件的宿主。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/component-tree.png" alt=""></p> <p>带层次结构的视图可以包含同一模块（<code>NgModule</code>）中组件的视图，也可以（而且经常会）包含其它模块中定义的组件的视图。</p> <h2 id="总结"><a href="#总结" class="header-anchor">#</a> 总结</h2> <p>本文简单介绍了 Angular 中元素、视图、模板、组件中与视图相关的一些定义，包括<code>ElementRef</code>，<code>TemplateRef</code>，<code>ViewRef</code>，<code>ComponentRef</code>和<code>ViewContainerRef</code>。</p> <p>其中，视图是 Angular 中应用程序 UI 的基本构建块，它是一起创建和销毁的最小元素组。</p> <p><code>ViewContainerRef</code>主要用于创建和管理内嵌视图或组件视图。组件可以通过配置模板来定义视图，与组件直接关联的模板会定义该组件的宿主视图，同时组件还可以包括内嵌视图。</p> <h3 id="参考"><a href="#参考" class="header-anchor">#</a> 参考</h3> <ul><li><a href="https://angular.cn/guide/architecture-components" target="_blank" rel="noopener noreferrer">Angular-组件简介<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://angular.cn/guide/glossary" target="_blank" rel="noopener noreferrer">Angular 词汇表<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://hackernoon.com/exploring-angular-dom-abstractions-80b3ebcfc02" target="_blank" rel="noopener noreferrer">Exploring Angular DOM manipulation techniques using ViewContainerRef<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/front-end-playground/edit/sourcecode/docs/front-end-others/deep-into-angular/angular-design-dom-define.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <blockquote>部分文章中使用了一些网站的截图，如果涉及侵权，请告诉我删一下谢谢~</blockquote> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本文版权归作者所有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。</div> <div>出处：被删的前端游乐场</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-metadata.html" class="prev">
          1.元数据和装饰器
        </a></span> <span class="next"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-zonejs.html">
          3.Zone区域之zone.js
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-9075" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty2.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/front-end-playground/assets/js/app.1e2670bf.js" defer></script><script src="/front-end-playground/assets/js/2.38d016d1.js" defer></script><script src="/front-end-playground/assets/js/3.e3f029cb.js" defer></script><script src="/front-end-playground/assets/js/107.b1eeddc4.js" defer></script>
  </body>
</html>
